package com.ayz.gateway.core.core.handlers;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;

import com.ayz.gateway.common.result.GatewayResult;
import com.ayz.gateway.common.result.ResponseCode;
import com.ayz.gateway.core.authorization.IAuth;
import com.ayz.gateway.core.context.config.Configuration;
import com.ayz.gateway.core.core.BaseHandler;
import com.ayz.gateway.core.core.HttpResponseParser;
import com.ayz.gateway.core.core.common.AgreementConstants;
import com.ayz.gateway.core.rpc.MappedMethod;
import com.ayz.gateway.core.session.http.HttpStatement;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import lombok.Data;
/**
 * @ClassName AuthorizationHandler
 * @Description TODO: 网关鉴权模块 使用JWT和Shiro框架完成鉴权模块
 * 如果用户没有资格访问直接返回
 * @Author 快乐的星球
 * @Date 2023/5/12 11:01
 * @Version 1.0
 **/
@Data
public class AuthorizationHandler extends BaseHandler<FullHttpRequest> {
    private static final Log LOG=Log.get(AuthorizationHandler.class);
    /**
     * 使用鉴权服务完成真正的鉴权功能
     */
    private IAuth authService;
    /**
     * 网关上下文配置项
     */
    private Configuration configuration;

    public AuthorizationHandler(IAuth authService, Configuration configuration) {
        this.authService = authService;
        this.configuration = configuration;
    }

    @Override
    public void openSession(ChannelHandlerContext channelHandlerContext, Channel channel, FullHttpRequest request) {
        LOG.info("网关处理鉴权逻辑;uri:{},method:{}",request.uri(),request.method());
        try {
            //TODO: 从通过到中取出上一个步骤的请求解析结果的HttpStatement
            HttpStatement httpStatement = channel.attr(AgreementConstants.HTTP_STATEMENT).get();
            //1: 根据配置判断是否需要鉴权处理
            MappedMethod mappedMethod = configuration.getMappedMethod(httpStatement.getHttpUri());
            boolean auth = mappedMethod.isAuth();
            try {
                if(auth){
                    //TODO: 进行服务鉴权
                    //得获取请求中的TOKEN
                    String uId = request.headers().get(AgreementConstants.UID_KEY);
                    String token = request.headers().get(AgreementConstants.TOKEN_KEY);
                    if(StrUtil.isEmpty(uId) || StrUtil.isEmpty(token)){
                        DefaultFullHttpResponse response=(DefaultFullHttpResponse) HttpResponseParser
                                .parse(GatewayResult.error(ResponseCode.REQUEST_PARAMETER_PARSE_FAILED,"当前RPC资源需要鉴权,当请求中缺少uid和token!"));
                        channel.writeAndFlush(response);
                    }else {
                        //进行具体的鉴权处理
                        boolean validate = authService.validate(uId, token);
                        if(validate){
                            LOG.info("网关鉴权模块鉴权通过!uri:{},method:{}",request.uri(),request.method());
                            request.retain();
                            //放行
                            channelHandlerContext.fireChannelRead(request);
                        }else {
                            //鉴权不通过
                            DefaultFullHttpResponse response=(DefaultFullHttpResponse) HttpResponseParser
                                    .parse(GatewayResult.error(ResponseCode.SERVER_REJECT_REQUEST,"鉴权不通过!"));
                            channel.writeAndFlush(response);
                        }
                    }

                }else {
                    //不需要鉴权,直接放行
                    request.retain();
                    channelHandlerContext.fireChannelRead(request);
                }
            }catch (Exception ex){
                LOG.warn("鉴权出错,禁止访问;uri:{},method:{}",request.uri(),request.method());
                DefaultFullHttpResponse response=(DefaultFullHttpResponse) HttpResponseParser.parse(
                        GatewayResult.error(ResponseCode.SERVER_REJECT_REQUEST,"服务端鉴权非法!"));
                channel.writeAndFlush(response);
            }

        }catch (Exception ex){
            LOG.warn("鉴权模块调用处理失败!uri:{},method",request.uri(),request.method());
            DefaultFullHttpResponse response=(DefaultFullHttpResponse) HttpResponseParser.parse(
                    GatewayResult.error(ResponseCode.SERVER_HANDLE_FAILED,"服务器网关鉴权模块处理失败!"));
            channel.writeAndFlush(response);
        }
    }
}
